import numpy as  np
import operator

datingTestSet2Path = 'datingTestSet2.txt'

def autoNorm(dataSet):
    '将数字特征转化为0到1的区间'
    minVals = np.min(dataSet, axis=0)
    maxVals = np.max(dataSet, axis=0)
    ranges = maxVals - minVals
    normDataSet = np.zeros(np.shape(dataSet))
    m = dataSet.shape[0]
    # 矩阵减法
    normDataSet = dataSet - np.tile(minVals, (m, 1))
    # '/' 为具体的特征值相除  numpy中矩阵除法为：linalg.slove(matA,matB)
    normDataSet = normDataSet / np.tile(ranges, (m, 1))
    return normDataSet, ranges, minVals


def fileMatrix(filename):
    fr = open(filename)
    arrayOLines = fr.readlines()
    numbersOfLines = len(arrayOLines)
    # 创建numbersOfLines * 3 的 元素为0的矩阵
    returnMatrix = np.zeros((numbersOfLines, 3))
    classLabelVectors = []
    index = 0
    for line in arrayOLines:
        # strip()参数为空时去掉line里面的空格或换行字符
        # str.strip([chars]);为去掉字符串头尾的指定字符 chars
        line = line.strip()
        listFormLine = line.split('\t')
        # 取前三个元素放到returnMatrix的第index个元素中
        returnMatrix[index, :] = listFormLine[0:3]
        # listFormLine[-1]  当index为负数的时候从末尾开始读数据，-1 为倒数第一数据
        classLabelVectors.append(int(listFormLine[-1]))
        index += 1
    return returnMatrix, classLabelVectors


def classify0(inX, dataSet, labels, k):
    # 计算距离
    dataSetSize = dataSet.shape[0]
    # tile（A,reqs）用于重复A  怎么重复根据reqs
    # 矩阵减法对应位置相减
    diffMat = np.tile(inX, (dataSetSize, 1)) - dataSet
    # **表示乘方
    sqDiffMat = diffMat ** 2

    sqDistances = sqDiffMat.sum(axis=1)
    distances = sqDistances ** 0.5
    sortedDistIndicies = distances.argsort()

    # 选择距离最小的k个点
    classCount = {}
    for i in range(k):
        voteIlabel = labels[sortedDistIndicies[i]]
        classCount[voteIlabel] = classCount.get(voteIlabel, 0) + 1

    # 排序 key表示按照什么参数进行排序    reverse = True 表示倒序排列
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse=True)
    return sortedClassCount[0][0]


def datingClassTest():
    hoRatio = 0.10
    datingDataMatrix, datingDataLables = fileMatrix(datingTestSet2Path)
    normMatrix, ranges, minVals = autoNorm(datingDataMatrix)
    m = normMatrix.shape[0]
    numTestVecs = int(m * hoRatio)
    errorCount = 0
    for i in range(numTestVecs):
        classifierResult = classify0(normMatrix[i, :], normMatrix[numTestVecs:m, :],
                                     datingDataLables[numTestVecs:m], 3)
        print('the classifier came back with: %d,the real answer is :%d' % (
            classifierResult, datingDataLables[i]))
        if (classifierResult != datingDataLables[i]): errorCount += 1.0
    print('the total error rate is :%f' % (errorCount / float(numTestVecs)))


datingClassTest()